package com.fgba.express.util;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fgba.express.comm.exception.BizException;
import com.fgba.express.comm.result.ResultCode;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author fgba
 */
@Data
@Component
@ConfigurationProperties(prefix = "we-chat")
@Slf4j
public class WeChatUtil {

    private String appid;
    /**
     * jwt密钥
     */
    private String secret;
    /**
     * 模板ID
     */
    private String tmplId;

    /**
     * 接口调用凭据
     */
    private String accessTokenJwt;
    /**
     * 跳转小程序类型：developer为开发版；trial为体验版；formal为正式版；默认为正式版
     */
    private String miniProgramState;
    /**
     * 进入小程序查看”的语言类型，支持zh_CN(简体中文)、en_US(英文)、zh_HK(繁体中文)、zh_TW(繁体中文)，默认为zh_CN
     */
    private String lang;

    @Resource
    private RedisUtil redisUtil;

//    @Async
//    public void send(String wxId, String noticeId, NoticeDto notice) throws IOException {
//        String url = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=" +
//                getAccessToken();
//        Template template = new Template(notice.getTitle(), notice.getContext(), notice.getReleaseTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")), notice.getReleaseName());
//        Map<String, Object> params = new HashMap<>(5);
//        params.put("touser", wxId);
//        params.put("template_id", tmplId);
//        params.put("page", "/pages/messageDetails/messageDetails?id=" + noticeId);
//        params.put("data", template);
//        params.put("miniprogram_state", miniProgramState);
//        params.put("lang", lang);
//
//        String result = getWeChatJSON(url, "POST", new Gson().toJson(params));
//        Map resultMap = new ObjectMapper().readValue(result, Map.class);
//        if (resultMap.get("errcode") != null) {
//            log.error("微信发送通知失败，异常编号：" + resultMap.get("errcode") + "，异常信息：" + resultMap.get("errmsg"));
//        }
//
//    }

    public String getAccessToken() throws IOException {
        String accessToken = (String) redisUtil.get("access_token");
        if (accessToken == null) {
            String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" +
                    getAppid() +
                    "&secret=" +
                    getSecret();
            String result = getWeChatJSON(url, "GET", null);
            Map resultMap = new ObjectMapper().readValue(result, Map.class);
            if (resultMap.get("errcode") == null) {
                accessToken = (String) resultMap.get("access_token");
                redisUtil.set("access_token", accessToken, Long.parseLong(resultMap.get("expires_in").toString()));
            } else {
                log.error("获取AccessToken失败，异常编号：" + resultMap.get("errcode") + "，异常信息：" + resultMap.get("errmsg"));
                throw new BizException(ResultCode.CALL_THIRD_PARTY_SERVICE_ERROR);
            }
        }
        return accessToken;

    }

    public String getOpenId(String code) throws IOException {
        String url = "https://api.weixin.qq.com/sns/jscode2session?appid=" +
                getAppid() +
                "&secret=" +
                getSecret() +
                "&js_code=" +
                code +
                "&grant_type=authorization_code";
        String result = getWeChatJSON(url, "GET", null);
        Map resultMap = new ObjectMapper().readValue(result, Map.class);
        if (resultMap.get("errcode") == null) {
            return (String) resultMap.get("openid");
        } else {
            log.error("获取OpenID失败，异常编号：" + resultMap.get("errcode") + "，异常信息：" + resultMap.get("errmsg"));
            throw new BizException(ResultCode.CALL_THIRD_PARTY_SERVICE_ERROR);
        }
    }

    private static String getWeChatJSON(String urlStr, String method, String params) throws IOException {
        URL url = new URL(urlStr);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setRequestMethod(method);
        conn.setDoInput(true);

        if ("POST".equals(method)) {
            conn.setDoOutput(true);
            conn.setUseCaches(false);
            conn.getOutputStream().write(params.getBytes(StandardCharsets.UTF_8));
        }
        conn.setConnectTimeout(5000);
        conn.setReadTimeout(5000);
        conn.connect();
        InputStream inputStream = conn.getInputStream();
        String result = new BufferedReader(new InputStreamReader(inputStream))
                .lines().collect(Collectors.joining(System.lineSeparator()));
        return result;
    }

    class Template {
        Map<String, String> thing2;
        Map<String, String> thing1;
        Map<String, String> time3;
        Map<String, String> thing4;

        public Template(String name, String context, String date, String releaseRealName) {
            Map<String, String> thing2Map = new HashMap<>(2);
            thing2Map.put("value", name);
            Map<String, String> thing1Map = new HashMap<>(2);
            thing1Map.put("value", context);
            Map<String, String> time3Map = new HashMap<>(2);
            time3Map.put("value", date);
            Map<String, String> thing4Map = new HashMap<>(2);
            thing4Map.put("value", releaseRealName);
            this.thing1 = thing1Map;
            this.thing2 = thing2Map;
            this.time3 = time3Map;
            this.thing4 = thing4Map;
        }

        public Map<String, String> getThing1() {
            return thing1;
        }

        public void setThing1(Map<String, String> thing1) {
            this.thing1 = thing1;
        }

        public Map<String, String> getThing2() {
            return thing2;
        }

        public void setThing2(Map<String, String> thing2) {
            this.thing2 = thing2;
        }

        public Map<String, String> getTime3() {
            return time3;
        }

        public void setTime3(Map<String, String> time3) {
            this.time3 = time3;
        }

        public Map<String, String> getThing4() {
            return thing4;
        }

        public void setThing4(Map<String, String> thing4) {
            this.thing4 = thing4;
        }
    }
}
